﻿using System;
using System.Linq;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Framework.Common;
using TFSTools.TFSLibrary.TestManagement;
using TFSTools.TFSLibrary.VersionControl;

namespace TFSTools.TFSLibrary
{
    public sealed class TFSConnection : ITFSConnection, IDisposable
    {
        private TfsTeamProjectCollection serverTeamProjectCollection = null;
        private TFSTeamProject selectedProject = null;

        private TFSWorkItemStore serviceWorkItemStore = null;
        private TFSVersionControl serviceVersionControl = null;
        private TFSGroupSecurity serviceGroupSecurity = null;
        private TFSTestManagement serviceTestManagement = null;

        internal TFSConnection()
        {
        }

        public TFSConnection(Uri tfsUri, string projectName)
        {
            this.Disconnect();

            this.serverTeamProjectCollection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(tfsUri);
            this.serverTeamProjectCollection.Connect(ConnectOptions.IncludeServices);
            this.serverTeamProjectCollection.EnsureAuthenticated();

            this.selectedProject = new TFSTeamProject(this, projectName);
        }

        public static TFSConnection LoadProjectSelectionFromUser()
        {
            using (var projectPicker = new TeamProjectPicker(TeamProjectPickerMode.SingleProject, false))
            {
                var userSelected = projectPicker.ShowDialog();

                if (projectPicker.SelectedTeamProjectCollection != null)
                {
                    var newConnection = new TFSConnection();

                    newConnection.serverTeamProjectCollection = projectPicker.SelectedTeamProjectCollection;
                    var projectInfo = projectPicker.SelectedProjects.FirstOrDefault();
                    
                    if (projectInfo != null)
                    {
                        newConnection.selectedProject = new TFSTeamProject(newConnection, projectInfo.Name);
                    }

                    return newConnection;
                }
            }

            return null;
        }

        public bool IsConnected
        {
            get { return this.serverTeamProjectCollection != null; }
        }

        public TFSWorkItemStore WorkItemStore 
        {
            get
            {
                if (this.serviceWorkItemStore == null)
                {
                    this.serviceWorkItemStore = new TFSWorkItemStore(this);
                }

                return this.serviceWorkItemStore;
            }
        }

        public TFSVersionControl VersionControl
        {
            get
            {
                if (this.serviceVersionControl == null)
                {
                    this.serviceVersionControl = new TFSVersionControl(this);
                }

                return this.serviceVersionControl;
            }
        }

        public TFSGroupSecurity GroupSecurity
        {
            get
            {
                if (this.serviceGroupSecurity == null)
                {
                    this.serviceGroupSecurity = new TFSGroupSecurity(this);
                }

                return this.serviceGroupSecurity;
            }
        }

        public TFSTestManagement TestManagement
        {
            get
            {
                if (this.serviceTestManagement == null)
                {
                    this.serviceTestManagement = new TFSTestManagement(this);
                }

                return this.serviceTestManagement;
            }
        }

        public TFSTeamProject FindProject(string projectName)
        {
            var project = this.VersionControl.Service.GetTeamProject(projectName);
            return new TFSTeamProject(this, project);
        }

        public TfsTeamProjectCollection SelectedTeamProjectCollection
        {
            get
            {
                this.CheckConnection();
                return this.serverTeamProjectCollection;
            }
        }

        public TFSTeamProject SelectedProject
        {
            get
            {
                return this.selectedProject;
            }
        }

        public string ServerName
        {
            get
            {
                return this.serverTeamProjectCollection.ToString();
            }
        }

        /// <summary>
        /// Gets the name or URI of the server.
        /// </summary>
        /// <value>The name or URI of the server.</value>
        public string ServerUri
        {
            get
            {
                this.CheckConnection();
                return this.serverTeamProjectCollection.Uri.ToString();
            }
        }

        /// <summary>
        /// Checks the connection.
        /// </summary>
        /// <exception cref="TFSNotConnectedException" />
        public void CheckConnection()
        {
            if (this.TryCheckConnection())
            {
                return;
            }

            throw new TFSNotConnectedException();
        }

        /// <summary>
        /// Checks the connection without throwing an exception.
        /// </summary>
        /// <returns><c>true</c> if connected; otherwise, <c>false</c>.</returns>
        public bool TryCheckConnection()
        {
            return (this.IsConnected && this.serverTeamProjectCollection != null);
        }

        /// <summary>
        /// Checks the connection and makes sure project is selected.
        /// </summary>
        /// <exception cref="TFSNotConnectedException" />
        public void CheckProjectConnection()
        {
            if (this.TryCheckProjectConnection())
            {
                return;
            }

            throw new TFSNotConnectedException();
        }

        /// <summary>
        /// Checks the connection and makes sure project is selected without throwing an exception.
        /// </summary>
        /// <returns><c>true</c> if connected; otherwise, <c>false</c>.</returns>
        public bool TryCheckProjectConnection()
        {
            return (this.TryCheckConnection() && this.selectedProject != null);
        }

        public override string ToString()
        {
            if (this.IsConnected && this.serverTeamProjectCollection != null)
            {
                return "TFSConnection: " + this.serverTeamProjectCollection.Name;
            }
            else
            {
                return "TFSConnection: Not connected";
            }
        }

        /// <summary>
        /// Disconnects this instance.
        /// </summary>
        private void Disconnect()
        {
            if (this.serverTeamProjectCollection != null)
            {
                this.serverTeamProjectCollection.Dispose();
                this.serverTeamProjectCollection = null;
            }
        }

        #region IDisposable Members

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            this.Disconnect();
        }

        #endregion
    }
}
